package com.bbcare.comm;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import redis.clients.jedis.Jedis;
import sun.misc.BASE64Encoder;

import com.aliyun.oss.ClientException;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsRequest;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsResponse;
import com.bbcare.sso.client.Account;
import com.bbcare.sso.client.Tenant;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * @name: 通用工具类
 * @author: DemonLee
 * @createTime: 2017.4.24
 * @description: 相关通用方法
 * @modify:
 *
 */

@SuppressWarnings("restriction")
public class ToolUtil {
    private final static Log logger = LogFactory.getLog(ToolUtil.class);

    // redis关闭
    public static void closeRedis(Jedis jedis) {
        if (null != jedis) {
            try {
                jedis.close();
                logger.warn("close redis connection...");
            } catch (Exception ex) {
                ex.printStackTrace();
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_REDIS_CONNECT_CLOSE_FAILED, "Redis缓存关闭失败!"));
            }
        }
        return;
    }

    // 拼装redis-key
    public static String assembleKey(List<String> varList) {
        if (null == varList || 0 == varList.size()) {
            return null;
        }
        StringBuffer keyBuffer = new StringBuffer();
        int k = 0;
        for (k = 0; k < varList.size(); k++) {
            keyBuffer.append(varList.get(k));
            keyBuffer.append(Constants.COLON_SPLIT_STR);
        }
        return keyBuffer.substring(0, keyBuffer.length() - Constants.COLON_SPLIT_STR.length());
    }

    // 类型转换，去掉unchecked cast warning
    @SuppressWarnings("unchecked")
    public static <T> T typeCast(Object obj) {
        return (T) obj;
    }

    /**
     * 校验上传文件的后缀名
     **/
    public static void checkFileSuffix(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "文件名为空！"));
        }
        int iPos = fileName.lastIndexOf(".");
        // 是否存在后缀名
        if (-1 == iPos) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    "上传的文件【" + fileName + "】扩展名为空！"));
        } else {
            String substring = fileName.substring(iPos + 1).toLowerCase();
            if (StringUtils.isBlank(substring)) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        "上传的文件【" + fileName + "】扩展名为空！"));
            }
        }
        // 后缀上哪种类型，待完善
        // String suffix = fileName.substring(iPos).toLowerCase();

        return;
    }

    /**
     * 校验入参根节点及json格式
     **/
    public static void checkInputRootNode(String arg) {
        if (StringUtils.isBlank(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "入参信息为空！"));
        }
        try {
            com.alibaba.fastjson.JSON.parseObject(arg);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                    Constants.API_INPUT_PARAMS_FORMAT_ERROR + "，非json格式！"));
        }

        return;
    }

    /**
     * 校验入参根节点、json格式以及业务data节点
     **/
    public static void checkInputRoot(String arg) {
        if (StringUtils.isBlank(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "入参信息为空！"));
        }
        com.alibaba.fastjson.JSONObject jsonArg = null;
        try {
            jsonArg = com.alibaba.fastjson.JSON.parseObject(arg);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                    Constants.API_INPUT_PARAMS_FORMAT_ERROR + "，非json格式！"));
        }

        Map<String, Object> mapIn = jsonArg.getJSONObject(Constants.INF_INPUTPARAM_COMMONFIELD);
        if (null == mapIn) {
            // 前台必须传data节点，否则报错返回
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，无data节点！"));
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持String类型为空校验
     **/
    public static void checkInputInfo(String checkNode, Map<String, Object> argInfo, Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarValue = "";
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarValue = "";
            chkVarStr = iter.next();
            chkVarValue = (String) checkVarInfo.get(chkVarStr);

            try {
                if (StringUtils.isBlank((String) argInfo.get(chkVarStr))) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarValue + "为空！"));
                }
            } catch (AppException e) {
                throw (e);
            } catch (Exception e) {
                List<Object> classIdList = ToolUtil.typeCast(argInfo.get(chkVarStr));// 文件id
                if (classIdList == null || classIdList.size() <= 0) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarValue + "为空！"));
                }

            }

        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持Integer类型为空及大于等于0校验
     **/
    public static void checkInputIntegerGe(String checkNode, Map<String, Object> argInfo,
            Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarName = "";
        Integer chkVarValue = null;
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarName = "";
            chkVarStr = iter.next();
            chkVarName = (String) checkVarInfo.get(chkVarStr);

            chkVarValue = (Integer) argInfo.get(chkVarStr);
            if (null == chkVarValue || chkVarValue < 0) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "为空或传值错误！"));
            }
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持Integer类型为空校验
     **/
    public static void checkInputIntegerNotNull(String checkNode, Map<String, Object> argInfo,
            Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarName = "";
        Integer chkVarValue = null;
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarName = "";
            chkVarStr = iter.next();
            chkVarName = (String) checkVarInfo.get(chkVarStr);

            chkVarValue = (Integer) argInfo.get(chkVarStr);
            if (null == chkVarValue) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "为空！"));
            }
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持各种类型的数据是否为空
     **/
    public static void checkInputMulti(String checkNode, Map<String, Object> argInfo,
            List<Map<String, Object>> checkVarList) {
        if (CollectionUtils.isEmpty(checkVarList)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarId = null;// 校验变量名
        String chkVarName = null;// 校验变量中文名
        Integer chkVarType = null;// 校验变量的类型
        Integer chkRuleType = null;// 校验规则
        int c = 0;
        int csize = checkVarList.size();
        Map<String, Object> chekVarMap = new HashMap<String, Object>();
        for (c = 0; c < csize; c++) {
            chekVarMap = checkVarList.get(c);
            chkVarId = (String) chekVarMap.get("chkVarId");
            chkVarName = (String) chekVarMap.get("chkVarName");
            chkVarType = (Integer) chekVarMap.get("chkVarType");
            chkRuleType = (Integer) chekVarMap.get("chkRuleType");

            switch (chkVarType) {
            // String
            case Constants.COMMON_TYPE_FOR_STRING: {
                if (Constants.CHECK_TYPE_FOR_NOTNULL == chkRuleType) {
                    // 非空
                    if (StringUtils.isBlank((String) argInfo.get(chkVarId))) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "为空！"));
                    }
                }
                break;
            }
            // Integer
            case Constants.COMMON_TYPE_FOR_INTEGER: {
                Integer chkVarValue = (Integer) argInfo.get(chkVarId);
                if (Constants.CHECK_TYPE_FOR_NOTNULL == chkRuleType) {
                    // 非空
                    if (null == chkVarValue) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "为空！"));
                    }
                } else if (Constants.CHECK_TYPE_FOR_NOTNULL_AND_GEZERO == chkRuleType) {
                    // 非空且大于等于0
                    if (null == chkVarValue || chkVarValue < 0) {
                        throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                                Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "传值错误！"));
                    }
                }
                break;
            }
            }
        }

        return;
    }

    /**
     * 校验入参中List节点是否为空 checkNode: 校验的节点名称; argList: 校验入参源; checkVarInfo: 待校验的变量
     * 暂时只支持String类型为空校验
     **/
    public static void checkInputList(String checkNode, List<Object> argList, Map<String, Object> checkVarInfo) {
        if (CollectionUtils.isEmpty(argList)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }

        int i = 0;
        int isize = argList.size();
        Map<String, Object> objMap = null;
        for (i = 0; i < isize; i++) {
            objMap = typeCast(argList.get(i));
            checkInputInfo(checkNode, objMap, checkVarInfo);
        }

        return;
    }

    /**
     * 入参分页信息校验
     **/
    public static void checkPageInfo(Map<String, Object> pageMap) {
        Integer page = 1;
        Integer rows = 20;
        if (!MapUtils.isEmpty(pageMap)) {
            page = (Integer) pageMap.get("page");
            if (null == page || page <= 0) {
                page = 1;
            }
            rows = (Integer) pageMap.get("rows");
            if (null == rows || rows <= 0) {
                rows = 20;
            }
        }
        pageMap.put("start", (page - 1) * rows);
        pageMap.put("end", rows);

        return;
    }

    // 获取上传文件的远程路径
    public static String getUploadFilePath(String basicPathName, String folderName) {
        if (StringUtils.isBlank(basicPathName)) {
            return "";
        }
        String basicPath = PropertiesUtils.getProperty(basicPathName);
        if (StringUtils.isBlank(basicPath)) {
            return "";
        }
        StringBuffer pathBuff = new StringBuffer();
        pathBuff.append(basicPath);
        if (StringUtils.isNotBlank(folderName)) {
            pathBuff.append(folderName);
            pathBuff.append(Constants.SLASH_STR);
        }

        return pathBuff.toString();
    }

    public static Map<String, Object> getSessionInfo(HttpServletRequest request) {
        Map<String, Object> outRet = new HashMap<String, Object>();

        HttpSession session = request.getSession(true);
        if (null == session) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_ISNULL, "session为空！"));
        }
        Account account = (Account) session.getAttribute(Constants.SESSION_ACCOUNT_KEY);
        if (null == account) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取session账号值为空！"));
        }
        Tenant tenant = (Tenant) account.getTenant();
        if (null == tenant) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取session租户值为空！"));
        }

        outRet.put("loginId", account.getUsername());
        outRet.put("authorName", account.getAlias());
        outRet.put("tenantId", tenant.getId());
        outRet.put("tenantName", tenant.getName());

        outRet.put("authorType", tenant.getType());
        outRet.put("authorId", account.getRelationId());

        // 租户类型：1、科室，2、医院，3、多中心，4、医联体
        outRet.put("groupType", tenant.getType());
        outRet.put("rootGroupId", tenant.getRootGroupId());
        if (Constants.TENANT_GROUP_TYPE_FOR_DEPT == tenant.getType()) {
            outRet.put("deptId", tenant.getRootGroupId());
        } else if (Constants.TENANT_GROUP_TYPE_FOR_HOSPITAL == tenant.getType()) {
            // TODO
        } else if (Constants.TENANT_GROUP_TYPE_FOR_MULCENTER == tenant.getType()) {
            // TODO
        } else if (Constants.TENANT_GROUP_TYPE_FOR_UNION == tenant.getType()) {
            // TODO
        }

        logger.warn("outRet==" + outRet.toString());

        return outRet;
    }

    public static String getPregnancyStr(int pregnancy) {
        StringBuilder builder = new StringBuilder();
        String week = String.valueOf(pregnancy / 7);
        String day = String.valueOf(pregnancy % 7);
        builder.append(week);
        builder.append("周");
        builder.append(day);
        builder.append("天");
        return builder.toString();
    }

    // 从问卷中解析用户基本信息
    public static Map<String, Object> parseUserInfoByQues(Map<String, Object> inPut) {
        Map<String, Object> inMap = new HashMap<String, Object>(inPut);
        Map<String, Object> outMap = new HashMap<String, Object>();
        // 手机号码
        String phoneNo = (String) inMap.get(Constants.QUESTION_ID_FOR_PHONENO);

        if (!StringUtils.isBlank(phoneNo)) {
            phoneNo = phoneNo.trim();
            outMap.put("phoneNo", phoneNo);
        }
        // 患者姓名
        String userName = (String) inMap.get(Constants.QUESTION_ID_FOR_PATIENTNAME);
        if (!StringUtils.isBlank(userName)) {
            userName = userName.trim();
            outMap.put("userName", userName);
            outMap.put("firstName", userName.substring(0, 1));
        }
        // 性别
        String gender = (String) inMap.get(Constants.QUESTION_ID_FOR_GENDER);
        if (!StringUtils.isBlank(gender)) {
            gender = gender.trim();
            // 转换性别
            if (Constants.GENDER_ALIAS_FOR_MALE.equals(gender)) {
                gender = Constants.GENDER_FOR_MALE;
            } else if (Constants.GENDER_ALIAS_FOR_FEMALE.equals(gender)) {
                gender = Constants.GENDER_FOR_FEMALE;
            } else if (!Constants.GENDER_FOR_MALE.equals(gender) && !Constants.GENDER_FOR_FEMALE.equals(gender)) {
                gender = Constants.GENDER_FOR_MALE;
            }
            outMap.put("gender", gender);
        }
        // 出生日期
        String birthday = (String) inMap.get(Constants.QUESTION_ID_FOR_BIRTHDAY);
        if (!StringUtils.isBlank(birthday)) {
            birthday = birthday.trim();
            outMap.put("birthday", birthday);
        }
        // 预产期
        String expectedDay = (String) inMap.get(Constants.QUESTION_ID_FOR_EXPECTEDDAY);
        if (!StringUtils.isBlank(expectedDay)) {
            expectedDay = expectedDay.trim();
            outMap.put("expectedDay", expectedDay);
        }

        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay)) {
            // 根据生日和预产期计算孕周
            int pregnancyDay = calPrenDayByBirthAndExpect(birthday, expectedDay);
            outMap.put("pregnancyDay", pregnancyDay);
        }

        if (0 == outMap.size()) {
            return null;
        }
        return outMap;
    }

    // 按照任务触发方式，计算任务执行时间
    public static String getExecuteTime(Map<String, Object> pIn) {
        logger.warn("getExecuteTime pIn==" + pIn.toString());

        String currDay = (String) pIn.get("currDay");
        int iPrenDay = Integer.parseInt("" + pIn.get("prenDay"));
        String birthDay = (String) pIn.get("birthDay");
        String executeType = (String) pIn.get("executeType");
        int iTaskSeq = Integer.parseInt("" + pIn.get("taskSeq"));
        // int iCycleDay = Integer.parseInt("" + pIn.get("cycleDay"));
        int ageDay = Integer.parseInt("" + pIn.get("ageDay"));
        int executeDay = Integer.parseInt("" + pIn.get("executeDay"));

        String executeTime = "";
        if (0 == iTaskSeq) {
            executeTime = currDay;
        }

        if (Constants.SCHEME_TASK_EXECUTE_TYPE_0.equals(executeType)) {
            // 0：应用后触发（当天建档+第一次随访，然后按周期进行第n次随访）
            if (1 == iTaskSeq) {
                executeTime = currDay;
            } else if (iTaskSeq >= 2) {
                executeTime = DateUtil.calcDay(currDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_1.equals(executeType)) {
            // 1：纠正年龄触发（37周以下用纠正年龄(2岁内)，其他用出生年龄）
            if (iTaskSeq >= 1) {
                if (ageDay <= (2 * 365) && iPrenDay < Constants.PATIENT_PREMATURE_PREGNANT_DAY) {
                    executeTime = DateUtil.calcDay(birthDay, "+",
                            (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + executeDay);
                } else {
                    executeTime = DateUtil.calcDay(birthDay, "+", executeDay);
                }
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_2.equals(executeType)) {
            // 2：出生年龄触发（当天建档，后续随访日期按出生日期+周期计算）
            if (iTaskSeq >= 1) {
                executeTime = DateUtil.calcDay(birthDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_3.equals(executeType)) {
            // 3：出院后触发（出院日建档，后续随访按照出院日期+周期计算）
            String outHospitalDay = (String) pIn.get("outHospitalDay");
            if (StringUtils.isEmpty(outHospitalDay)) {
                throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_OUTHOSPITAL_PARAM,
                        "出院后触发随访任务需要填写出院日期！");
            }
            if (0 == iTaskSeq) {
                executeTime = outHospitalDay;
            } else {
                executeTime = DateUtil.calcDay(outHospitalDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_4.equals(executeType)) {
            // 4：初检孕周日期触发（孕产妇随访，初次孕检日建档）
            Integer firstChkPregWeek = (Integer) pIn.get("firstChkPregWeek");
            if (null == firstChkPregWeek || firstChkPregWeek <= 0) {
                throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "孕产妇随访任务需要填写初检孕周！");
            }
            if (0 == iTaskSeq) {
                executeTime = currDay;
            } else {
                int dealDay = executeDay - firstChkPregWeek * 7;
                if (dealDay <= 0) {
                    dealDay = 0;
                }
                executeTime = DateUtil.calcDay(currDay, "+", dealDay);
            }
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_UNKNOWN, "任务触发方式未定义！"));
        }

        return executeTime;
    }

    // 根据任务规则，计算开始结束时间
    public static Map<String, Object> getTaskRuleTime(Map<String, Object> pIn) {
        Map<String, Object> outMap = new HashMap<String, Object>();

        // String currDay = (String) pIn.get("currDay");
        int iPrenDay = Integer.parseInt("" + pIn.get("prenDay"));
        String birthDay = (String) pIn.get("birthday");
        String ruleType = (String) pIn.get("ruleType");
        int beginDay = Integer.parseInt("" + pIn.get("beginDay"));
        int endDay = Integer.parseInt("" + pIn.get("endDay"));
        int ageDay = Integer.parseInt("" + pIn.get("ageDay"));
        String beginDate = "";
        String endDate = "";

        // 纠正月龄
        if (Constants.TASK_TYPE_SCHEME_SELFREPORT_MONTHAGE.equals(ruleType)) {
            if (ageDay <= (2 * 365) && iPrenDay < Constants.PATIENT_PREMATURE_PREGNANT_DAY) {
                beginDate = DateUtil.calcDay(birthDay, "+",
                        (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + beginDay);
                endDate = DateUtil.calcDay(birthDay, "+", (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + endDay);
            } else {
                beginDate = DateUtil.calcDay(birthDay, "+", beginDay);
                endDate = DateUtil.calcDay(birthDay, "+", endDay);
            }
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_UNKNOWN, "任务触发方式未定义！"));
        }
        outMap.put("beginDate", beginDate);
        outMap.put("endDate", endDate);

        return outMap;
    }

    // 根据出生日期和预产期计算孕周，返回天数
    public static int calPrenDayByBirthAndExpect(String birthday, String expectedDay) {
        int day = 0;
        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay)) {
            try {
                Date birthdayDate = DateUtil.getDate_8(birthday);
                Date expectedDate = DateUtil.getDate_8(expectedDay);

                Calendar exp = Calendar.getInstance();
                Calendar bir = Calendar.getInstance();
                exp.setTime(expectedDate);
                bir.setTime(birthdayDate);
                long expTime = exp.getTimeInMillis();
                long birTime = bir.getTimeInMillis();
                long bet = birTime - expTime;
                day = Constants.PATIENT_NORMAL_PREGNANT_DAY + (int) (bet / 86400000L);
                // 后续考虑最小孕周和最大孕周的情况，加校验，这里先只校验小于0的情况
                if (day < 0) {
                    day = 0;
                }
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
            }
        }
        return day;
    }

    // 根据生日计算年龄，返回天数
    public static int getBirthAgeDay(String birthday) {
        int day = 0;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            long bet = now.getTimeInMillis() - cal.getTimeInMillis();
            if (bet < 0L) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_BIRTHDAY_EXPEND_NOW, "时间计算错误，出生日期大于当前时间！"));
            }
            day = (int) (bet / 86400000L);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        return day;
    }

    // 根据生日和当前时间计算年龄
    public static String getAgeByDate(String birthday, Date currentDate) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        now.setTime(currentDate);

        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!cal.before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。
            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year > 0) {
                builder.append(year).append("岁");
            }

            if (month > 0 && year >= 0) {
                builder.append(month).append("月");
            } else if (day > 0 && month >= 0 && year >= 0) {
                if (day > 7) {// 展示周
                    week = day / 7;
                    builder.append(week).append("周");
                } else {
                    builder.append(day).append("天");
                }
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 根据生日计算年龄
    public static String getAgeMonDayByBirthday(String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        if (StringUtils.isEmpty(birthday)) {// 如果没有生日 则返回空
            return null;
        }
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。
            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            // 暂时展示 一个单位 岁、或月、天
            if (year > 0) {
                builder.append(year).append("岁");
            }
            if (month > 0 && year >= 0) {
                builder.append(month).append("月龄");
            }
            if (day > 0 && month >= 0 && year >= 0) {
                builder.append(day).append("天");
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 根据生日计算年龄
    public static String getAgeByBirthday(String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year > 0) {
                builder.append(year).append("岁");
            }

            if (month > 0 && year >= 0) {
                builder.append(month).append("个月");
            } else if (day > 0 && month >= 0 && year >= 0) {
                if (day > 7) {// 展示周
                    week = day / 7;
                    builder.append(week).append("周");
                } else {
                    builder.append(day).append("天");
                }
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 矫正年龄
    public static Long getCorrect(String birthday, Integer pregnancyWeek) {
        // TODO Auto-generated method stub
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Long time = new Date().getTime();
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                time = birthdayDate.getTime();
            } else {
                time = birthdayDate.getTime() + (280 - pregnancyWeek) * 86400000L;
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return time;
    }

    /**
     * 生成带普通二维码文件流
     *
     * @return
     * @throws IOException
     */
    public static byte[] createQrCode(String content) throws IOException {

        ByteArrayOutputStream out = null;
        ByteArrayOutputStream logoQRcode = new ByteArrayOutputStream();
        try {
            out = new ByteArrayOutputStream();
            BufferedImage bim = getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, getDecodeHintType());
            // ImageIO.write(bim, "jpeg", file);
            ImageIO.write(bim, "jpeg", out);
            return out.toByteArray();
        } catch (Throwable e) {
            logger.error("生成二维码文件报错", e);
            ;
            throw new AppException("1200111", "生成二维码失败");
        } finally {
            if (null != out) {
                out.close();
            }
            if (null != logoQRcode) {
                logoQRcode.close();
            }
        }
    }

    /**
     * 生成带logo二维码文件流
     *
     * @return
     * @throws IOException
     */
    public static byte[] createQrCodeAndLogo(String content, String logoUrl) throws IOException {

        ByteArrayOutputStream out = null;
        ByteArrayInputStream in = null;
        ByteArrayOutputStream logoQRcode = new ByteArrayOutputStream();
        try {
            out = new ByteArrayOutputStream();
            BufferedImage bim = getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, getDecodeHintType());
            // ImageIO.write(bim, "jpeg", file);
            ImageIO.write(bim, "jpeg", out);
            // zp.addLogo_QRCode(out, new File("D:/logo.png"), new
            // LogoConfig());
            in = new ByteArrayInputStream(out.toByteArray());

            addLogo_QRCode(in, new URL(logoUrl), new LogoConfig(), logoQRcode);

            return logoQRcode.toByteArray();
        } catch (Throwable e) {
            logger.error("生成二维码文件报错", e);
            ;
            throw new AppException("1200111", "生成二维码失败");
        } finally {
            if (null != in) {
                in.close();
            }
            if (null != out) {
                out.close();
            }
            if (null != logoQRcode) {
                logoQRcode.close();
            }
        }

    }

    /**
     * 给二维码图片添加Logo 返回输出流
     *
     * @param qrPic
     * @param logoPic
     */
    public static void addLogo_QRCode(InputStream in, URL logoPic, LogoConfig logoConfig, ByteArrayOutputStream out) {
        try {
            // ByteArrayOutputStream out = new ByteArrayOutputStream();
            if (null == in) {
                logger.error("file not find !");
                throw new AppException("1200111", "logo图标不存在");
            }
            /**
             * 读取二维码图片，并构建绘图对象
             */
            BufferedImage image = ImageIO.read(in);
            Graphics2D g = image.createGraphics();

            /**
             * 读取Logo图片
             */
            BufferedImage logo = ImageIO.read(logoPic);
            /**
             * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
             */
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10)
                    : logo.getWidth(null),
                    heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10)
                            : logo.getHeight(null);
            // 计算图片放置位置
            /**
             * logo放在中心
             */
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;
            /**
             * logo放在右下角
             */
            /*
             * int x = (image.getWidth() - widthLogo); int y =
             * (image.getHeight() - heightLogo);
             */
            // 开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();
            // ImageIO.write(image, "png", new File("D:/"/*+new
            // Date().getTime()*/+"test.png"));
            ImageIO.write(image, "png", out);
        } catch (Exception e) {
            logger.error("生成二维码输出流报错", e);
            ;
            e.printStackTrace();
        }

    }

    /**
     * 给二维码图片添加Logo
     *
     * @param qrPic
     * @param logoPic
     */
    public void addLogo_QRCode(File qrPic, File logoPic, LogoConfig logoConfig) {
        try {
            if (!qrPic.isFile() || !logoPic.isFile()) {
                logger.error("file not find !");
                throw new AppException("1200113", "生成二维码失败");
            }

            /**
             * 读取二维码图片，并构建绘图对象
             */
            BufferedImage image = ImageIO.read(qrPic);
            Graphics2D g = image.createGraphics();

            /**
             * 读取Logo图片
             */
            BufferedImage logo = ImageIO.read(logoPic);
            /**
             * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
             */
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10)
                    : logo.getWidth(null),
                    heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10)
                            : logo.getHeight(null);

            // 计算图片放置位置
            /**
             *
             * logo放在中心
             */
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;
            /**
             * logo放在右下角
             */
            /*
             * int x = (image.getWidth() - widthLogo); int y =
             * (image.getHeight() - heightLogo);
             */
            // 开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();

            ImageIO.write(image, "png", new File("D:/"/*
                                                       * +new Date().getTime()
                                                       */
                    + "test.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成二维码bufferedImage图片
     *
     * @param content
     *            编码内容
     * @param barcodeFormat
     *            编码类型
     * @param width
     *            图片宽度
     * @param height
     *            图片高度
     * @param hints
     *            设置参数
     * @return
     */
    public static BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width,
            int height, Map<EncodeHintType, ?> hints) {
        MultiFormatWriter multiFormatWriter = null;
        BitMatrix bm = null;
        BufferedImage image = null;
        try {
            multiFormatWriter = new MultiFormatWriter();

            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
            bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);

            bm = deleteWhite(bm);
            int w = bm.getWidth();
            int h = bm.getHeight();
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

            // 开始利用二维码数据创建Bitmap图片，分别设为白（0xFFFFFFFF）黑（0xFF000000）两色
            for (int x = 0; x < w; x++) {
                for (int y = 0; y < h; y++) {
                    image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE);
                }
            }
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return image;
    }

    // 删除二维码边框
    public static BitMatrix deleteWhite(BitMatrix matrix) {
        int[] rec = matrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;

        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (matrix.get(i + rec[0], j + rec[1]))
                    resMatrix.set(i, j);
            }
        }
        return resMatrix;
    }

    /**
     * 设置二维码的格式参数
     *
     * @return
     */
    public static Map<EncodeHintType, Object> getDecodeHintType() {
        // 用于设置QR二维码参数
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        // 设置QR二维码的纠错级别（H为最高级别）具体级别信息
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置编码方式
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        hints.put(EncodeHintType.MAX_SIZE, 350);
        hints.put(EncodeHintType.MIN_SIZE, 100);

        return hints;
    }

    /**
     * 验证是否为手机号
     *
     * @param phoneNo
     *            手机号
     * @return wuyz
     */
    public static boolean checkPhoneNo(String phoneNo) {
        Pattern pattern = Pattern.compile("^1[\\d]{10}");
        Matcher matcher = pattern.matcher(phoneNo);
        return matcher.matches();
    }

    // 阿里注册短信
    public static Boolean sendALISms(String phoneNo, String context, String smsType) throws Exception {
        Boolean flag = false;
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "KxOYldlzgNbV7LPk",
                "Do7wFceam0fGLK3ovbJd2J2rZQRyUh");
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Sms", "sms.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);
        SingleSendSmsRequest request = new SingleSendSmsRequest();
        String templateCode = "SMS_33810202"; // 注册
        if (smsType.equals("02")) {
            templateCode = "SMS_33910139"; // 找回密码
        } else if (smsType.equals("07")) {
            templateCode = "SMS_67255538"; // 提现
        }

        try {
            request.setSignName("贝生医疗");
            request.setTemplateCode(templateCode);
            request.setParamString("{\"code\":\"" + context + "\"}");
            request.setRecNum(phoneNo);
            SingleSendSmsResponse httpResponse = client.getAcsResponse(request);
            if (httpResponse != null) {
                if (httpResponse.getRequestId() != null) {
                    flag = true;
                } else {
                    flag = false;
                }
            } else {
                flag = false;
            }
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return flag;
    }

    // 亿美软通短信-通知类
    public static int sendYMsms(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = "【贝生医疗】" + context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    // 亿美软通短信-通知类
    public static int sendYMsms2(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();// 获取当前系统时间
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        // System.out.println("短信即将发送请注意:" + seqId);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        // System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    public static int sendYMsms3(String phoneNo, String context) throws Exception {
        String sn = "6SDK-EMY-6666-RHWLN";// 软件序列号,请通过亿美销售人员获取
        String key = "203969";// 序列号首次激活时自己设定
        // String password = "203969";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://sdktaows.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        context = URLEncoder.encode(context, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + context + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";

        // String ret = SDKHttpClient.registAndLogout(url, param);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        System.out.println(param);
        System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    /**
     * 产生随机码
     *
     * @param num
     *            多少位随机码
     * @return
     *
     * @version 1.0.0
     */
    public static String getRandom(int num) {
        Random random = new Random();
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < num; i++) {
            str.append(Math.abs(random.nextInt() % 10));
        }

        return str.toString();
    }

    // 获取openId
    public static String getOpenId(String code) throws Exception {
        String msg = "";
        String openId = null;
        URL url = null;
        HttpURLConnection connection = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        InputStream is = null;
        DataInputStream dis = null;
        String sdUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
        try {
            url = new URL(sdUrl);
            trustAllHttpsCertificates();
            connection = (HttpsURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            connection.setRequestProperty("Proxy-Connection", "Keep-Alive");
            connection.setDoOutput(true);
            connection.setDoInput(true);

            logger.info(sdUrl + "appid=" + Constants.appid + "&secret=" + Constants.appsecret + "&code=" + code
                    + "&grant_type=authorization_code");

            os = connection.getOutputStream();
            dos = new DataOutputStream(os);
            dos.write(("appid=" + Constants.appid + "&secret=" + Constants.appsecret + "&code=" + code
                    + "&grant_type=authorization_code").getBytes("UTF-8"));
            dos.flush();
            is = connection.getInputStream();
            dis = new DataInputStream(is);
            byte d[] = new byte[dis.available()];
            dis.read(d);
            String rs = new String(d, "UTF-8");
            if (rs != null) {
                logger.info("return message = " + rs);
                msg = rs;
                JSONObject jsObject = JSONObject.fromObject(msg);
                if (jsObject.containsKey("openid")) {
                    openId = jsObject.getString("openid");
                    logger.info("openId:" + openId);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }

            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }

            if (connection != null) {
                connection.disconnect();
            }
        }
        return openId;
    }

    // 获取openId
    public static String getWechatInf(String sdUrl, String json) throws Exception {
        logger.info(sdUrl + "--" + json);
        String msg = "";
        URL url = null;
        HttpURLConnection connection = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            url = new URL(sdUrl);
            trustAllHttpsCertificates();
            connection = (HttpsURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            connection.setRequestProperty("Proxy-Connection", "Keep-Alive");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);

            os = connection.getOutputStream();
            if (!StringUtils.isEmpty(json)) {
                os.write(json.getBytes("UTF-8"));// 传入参数
            }
            dos = new DataOutputStream(os);
            dos.flush();
            is = connection.getInputStream();
            dis = new DataInputStream(is);
            byte d[] = new byte[dis.available()];
            dis.read(d);
            String rs = new String(d, "UTF-8");
            if (rs != null) {
                logger.info("return message = " + rs);
                msg = rs;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }

            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }

            if (connection != null) {
                connection.disconnect();
            }
        }
        return msg;
    }

    public static void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
        javax.net.ssl.TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }
    }

    public static Map<String, Object> appadd(String a, com.alibaba.fastjson.JSONObject jsonTow) {
        JSONObject node1 = JSONObject.fromObject(a);
        Iterator<?> it = node1.keys();
        Map<String, Object> map = new HashMap<String, Object>();
        while (it.hasNext()) {
            String key = it.next().toString();
            map.put(node1.getString(key), jsonTow.getString(key));
        }
        return map;
    }

    // 将json串转换陈map
    public static Map<String, Object> mapTojson(String a) {
        // System.out.println(a);
        JSONObject node1 = JSONObject.fromObject(a);
        Iterator<?> it = node1.keys();
        Map<String, Object> map = new HashMap<String, Object>();
        while (it.hasNext()) {
            String key = it.next().toString();
            map.put(key, node1.getString(key));
        }
        return map;
    }

    /**
     * 处理问卷模板实现增删改
     *
     * @author wuyz
     * @param map
     *            入参信息
     * @return String 返回json串
     *
     **/
    public static String changeJson(Map<String, Object> map) {
        String str = map.get("TemplData").toString();// 个人问卷模板json串
        String str1 = map.get("questions").toString();// 需要操作的模板json串
        String code = map.get("code").toString();// 操作类型
        JSONArray node11 = JSONArray.fromObject(str);
        JSONObject node12 = JSONObject.fromObject(node11.getJSONObject(0));
        JSONArray node13 = node12.getJSONArray("children");
        JSONArray node14 = JSONArray.fromObject(str1);
        if (code.equals(Constants.HANDLE_TYPE_CHANGE)) {// 修改
            for (int i = 0; i < node13.size(); i++) {
                JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                for (int j = 0; j < node14.size(); j++) {
                    JSONObject job1 = node14.getJSONObject(j);
                    // System.out.println(i + ":" + job.get("id"));
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        // System.out.println(job.get("id"));
                        node13.set(i, job1);
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);
            // System.out.println(node11.toString());
        } else if (code.equals(Constants.HANDLE_TYPE_ADD)) {// 增加
            for (int i = 0; i < node14.size(); i++) {
                JSONObject job = node14.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                for (int j = 0; j < node13.size(); j++) {
                    JSONObject job1 = node13.getJSONObject(j);
                    // 去除已经存在的数据
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        System.out.println(job.get("id"));
                        break;
                    } else if (j == node13.size() - 1) {
                        node13.add(job);
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);

        } else if (code.equals(Constants.HANDLE_TYPE_DELETE)) {// 删除
            for (int i = 0; i < node13.size(); i++) {
                JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                for (int j = 0; j < node14.size(); j++) {
                    JSONObject job1 = node14.getJSONObject(j);
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        node13.remove(i);
                        i--;
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);
            // System.out.println(node11.toString());
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_QUEUE_NOT_EXIST, "无此操作类型，请联系统管理员！"));
        }
        return node11.toString();
    }

    /**
     * 处理出参实现数据匹配
     *
     * @author wuyz
     * @param jsonStr
     *            模板json串，map 数据集合
     * @return String 返回json串
     *
     **/
    public static JSONArray matching(String jsonStr, HashMap<String, Object> map) {
        if (map == null || map.size() <= 0) {
            return null;
        }
        JSONArray node11 = JSONArray.fromObject(jsonStr);
        JSONObject node12 = JSONObject.fromObject(node11.getJSONObject(0));
        JSONArray node13 = node12.getJSONArray("children");
        Set<String> keys = map.keySet();
        for (int i = 0; i < node13.size(); i++) {
            JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray数组，把每一个对象转成
            // 匹配对应的key
            for (String key : keys) {
                if (job.containsValue(key)) {
                    job.put("checked", "0");
                    node13.set(i, job);
                    break;
                } else {
                    job.put("checked", "1");
                    node13.set(i, job);
                }
            }

        }
        node12.put("children", node13);
        node11.set(0, node12);
        // System.out.println(node11.toString());
        return node11;
    }

    /**
     * md5加密函数 入参参数描述：
     *
     * @param sourceStr
     *            String 需要加密的字符串
     * @param flag
     *            int 需要加密的位数：（1）32：返回32位加密串 （2）16：返回16位加密串 返回参数：
     * @return sourceStr String MD5加密后的字符串
     * @createTime 2017.06.13
     * @author wuyz
     *
     **/

    public static String MD5Encrept(String sourceStr, int flag) throws Exception {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(sourceStr.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            if (flag == 32) {
                result = buf.toString();
            } else {
                result = buf.toString().substring(8, 24);
            }
            //// System.out.println("MD5(" + sourceStr + ",32) = " + result);
            //// System.out.println("MD5(" + sourceStr + ",16) = " +
            //// buf.toString().substring(8, 24));
        } catch (NoSuchAlgorithmException e) {
            throw new NoSuchAlgorithmException(e.toString());
        }

        return result;
    }

    /**
     * utf-8编码格式转换 输入参数：
     *
     * @param sourceStr
     *            String 需要转换的GBK的字符串 输出参数
     * @param xmlUTF8
     *            String 转成utf-8格式后的字符串
     * @author wuyz
     * @createTime 2017.06.13
     **/
    public static String getUTF8XMLString(String sourceStr) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append(sourceStr);
        String xmString = "";
        String xmlUTF8 = "";
        try {
            xmString = new String(sb.toString().getBytes("UTF-8"));
            xmlUTF8 = URLEncoder.encode(xmString, "UTF-8");
            // System.out.println("utf-8 编码：" + xmlUTF8) ;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return xmlUTF8;
    }

    /**
     * SHA-256 和 SHA-512j加密 输入参数：
     *
     * @param strText
     *            String 需要加密的字符串
     * @param strType
     *            String SHA-256 和 SHA-512 两种 Hash 算法 输出参数
     * @param 加密后的出参
     *            String 异或运算后的字符串
     * @author wuyz
     * @throws UnsupportedEncodingException
     * @throws Exception
     * @createTime 2017.06.13
     **/
    public static String changeToSHA(String strText, String strType) throws UnsupportedEncodingException {

        // 返回值
        String strResult = "";

        // 是否是有效字符串
        if (strText != null && strText.length() > 0) {
            try {
                // SHA 加密开始
                // 创建加密对象 并傳入加密類型
                MessageDigest messageDigest = MessageDigest.getInstance(strType);
                // 传入要加密的字符串
                messageDigest.update(strText.getBytes("UTF-8"));
                // 得到 byte 类型结果
                byte byteBuffer[] = messageDigest.digest();
                BASE64Encoder encode = new BASE64Encoder();
                strResult = encode.encode(byteBuffer);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        // System.out.println(strResult);
        strResult = strResult.toLowerCase();
        return strResult;
    }

    /**
     * 字符串间的异或运算 输入参数：
     *
     * @param StrOne
     *            String 进行异或运算字符串
     * @param StrTow
     *            String 进行异或运算字符串 输出参数
     * @param xorstr
     *            String 异或运算后的字符串
     * @author wuyz
     * @throws Exception
     * @createTime 2017.06.13
     **/
    public static String twoStringXor(String StrOne, String StrTow) throws Exception {
        // 运算时计算长度以StrTow和StrOne值中字符长度短的为准
        byte b1[] = StrOne.getBytes("UTF-8");
        ;
        byte b2[] = StrTow.getBytes("UTF-8");
        ;
        // 定义一个BASE64Encoder
        BASE64Encoder encode = new BASE64Encoder();
        // 将byte[]转换为base64
        // 新建一个BASE64Decoder
        // BASE64Decoder decode = new BASE64Decoder();
        byte longbytes[], shortbytes[];
        if (b1.length >= b2.length) {
            longbytes = b1;
            shortbytes = b2;
        } else {
            longbytes = b2;
            shortbytes = b1;
        }
        byte xorstr[] = new byte[shortbytes.length];
        int i = 0;
        for (; i < shortbytes.length; i++) {
            xorstr[i] = (byte) ((int) shortbytes[i] ^ (int) longbytes[i]);
        }

        /*
         * for (;i<longbytes.length;i++){ xorstr[i] = longbytes[i]; }
         */
        String base64 = encode.encode(xorstr);
        return base64;
    }

    /**
     * xml解析函数，转换成map 入参参数描述：
     *
     * @param Str
     *            String xml字符串 返回参数：
     * @return map Map 放回map
     * @createTime 2017.06.22
     * @author wuyz
     **/
    public static List<Map<String, Object>> FormatXml(String Str) throws Exception {
        // 将xml转换成map
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        try {
            // 将xml格式字符串转化为DOM对象
            org.dom4j.Document document = DocumentHelper.parseText(Str);
            // 获取根结点对象
            Element rootElement = document.getRootElement();
            // 循环根节点，获取其子节点
            int in = 0;
            for (Iterator<?> iter = rootElement.elementIterator(); iter.hasNext();) {
                Element element = (Element) iter.next(); // 获取标签对象
                // 获取该标签对象的属性
                // System.out.println(element);
                List<?> attr = element.attributes();
                Map<String, Object> map = new HashMap<String, Object>();
                // 取标签属性值
                for (int i = 0; i < attr.size(); i++) {
                    Attribute attrid = (Attribute) attr.get(i);
                    String attrVal = attrid.getValue();
                    String attrName = attrid.getName();
                    map.put(attrName, attrVal);
                }
                // 循环第一层节点，获取其子节点
                // 取标签间的值
                for (Iterator<?> iterInner = element.elementIterator(); iterInner.hasNext();) {
                    // 获取标签对象
                    Element elementOption = (Element) iterInner.next();
                    // 获取该标签对象的名称
                    String tagName = elementOption.getName();
                    // 获取该标签对象的内容
                    String tagContent = elementOption.getTextTrim();
                    // 输出内容
                    map.put(tagName, tagContent);
                }
                // 定义一个list
                list.add(in, map);
                in++;
                // System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    // 数字校验
    public static boolean isNumeric(String str) {
        if (null == str) {
            return false;
        }
        Pattern pattern = Pattern.compile("([0-9]+\\.?[0-9]+)|([1-9]\\d*)");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    // 日期转星期
    public static Map<String, Object> dateToWeek(String datetime) {
        Map<String, Object> dateMap = new HashMap<String, Object>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        Date datet = null;
        try {
            datet = f.parse(datetime);
            cal.setTime(datet);
        } catch (ParseException e) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        int kk = cal.get(Calendar.DAY_OF_WEEK);
        int w = kk - 1; // 指示一个星期中的某天
        if (w < 0)
            w = 0;
        dateMap.put("dayIndex", w);
        dateMap.put("weekStr", Constants.dayOfWeek[w]);

        return dateMap;
    }

    // 根据随访任务时间和门诊排班，计算下次随访时间
    public static List<String> calcNextDate(Map<String, Object> pIn) {
        String beginTime = (String) pIn.get("beginTime");
        String endTime = (String) pIn.get("endTime");
        String scheduleType = (String) pIn.get("scheduleType");
        List<String> outList = new ArrayList<String>();

        List<Map<String, Object>> scheduleList = typeCast(pIn.get("scheduleList"));
        if (!CollectionUtils.isEmpty(scheduleList)) {
            Map<String, Object> dateMap = new HashMap<String, Object>();
            Map<String, Object> schMap = new HashMap<String, Object>();
            String timeStr = beginTime;
            int dayIndex = 0;
            String weekStr = "";
            String workDay = "";
            int workPeriod = 0;
            int scize = scheduleList.size();
            int st = 0;
            for (; timeStr.compareTo(endTime) <= 0;) {
                if (Constants.DEPT_OUTPATIENT_SCHEDULE_WEEKLY.equals(scheduleType)) {
                    // 按周排班
                    dateMap = dateToWeek(timeStr);
                    dayIndex = (Integer) dateMap.get("dayIndex");
                    weekStr = (String) dateMap.get("weekStr");
                    for (st = 0; st < scize; st++) {
                        schMap = scheduleList.get(st);
                        workDay = (String) schMap.get("workDay");
                        workPeriod = Integer.parseInt("" + schMap.get("workPeriod"));

                        if (workDay.equals("" + dayIndex)) {
                            StringBuffer scheduleStr = new StringBuffer();
                            scheduleStr.append(timeStr);
                            scheduleStr.append(Constants.COLON_SPLIT_STR);
                            scheduleStr.append(weekStr);
                            scheduleStr.append(Constants.timeOfDay[workPeriod]);
                            outList.add(scheduleStr.toString());
                        }
                    }

                    timeStr = DateUtil.calcDay2(timeStr, "+", 1);
                } else if (Constants.DEPT_OUTPATIENT_SCHEDULE_MONTHLY.equals(scheduleType)) {
                    // 按月排班
                } else if (Constants.DEPT_OUTPATIENT_SCHEDULE_DATE.equals(scheduleType)) {
                    // 按具体日期排班
                }
            }
        }

        return outList;
    }

    /**
     * 将字符串转换成Map结构
     *
     * @param str
     *            需要转换的字符串
     * @return Map结构数据
     * @throws ParseException
     */
    public static Map<String, Object> stringToMap(String str) {
        Map<String, Object> map = new HashMap<String, Object>();
        str = str.replaceAll("\\s*", "");
        ;
        if (str.startsWith("{"))
            str = str.substring(1, str.length());
        if (str.endsWith("}"))
            str = str.substring(0, str.length() - 1);
        String[] datas = str.split(",");
        for (String data : datas) {
            String[] d = data.split("=");
            if (d.length == 2) {
                map.put(d[0], d[1]);
            } else {
                int index = data.indexOf("=");
                if (index > 0)
                    map.put(data.substring(0, index), data.substring(index + 1, data.length()));
            }
        }
        return map;
    }

    // 根据生日计算年龄
    /**
     * 年龄格式：小于三个月的显示几周几天，小于1岁的显示几月龄几天，大于一岁的显示几岁几月龄， 大于六岁的只显示岁。对于孕周小于37周的
     *
     * @param birthday
     * @return
     * @throws ParseException
     */
    public static String getCommAgeByBirthday(String testTime, String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        now.setTime(DateUtil.getDate_8(testTime));

        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year >= 6) {
                builder.append(year).append("岁");
            } else {
                if (year >= 1) {
                    builder.append(year).append("岁");
                    if (month > 0) {
                        builder.append(month).append("月龄");
                    }
                }

                if (year < 1) {
                    if (year == 0 && month >= 3) {
                        builder.append(month).append("月龄");
                        if (day > 0) {
                            builder.append(day).append("天");
                        }
                    } else {
                        if (day > 0 || month > 0) {
                            day = (int) ((DateUtil.getDate_8(testTime).getTime()
                                    - DateUtil.getDate_8(birthday).getTime()) / 24 / 3600 / 1000);
                            week = day / 7;
                            builder.append(week).append("周");
                            int dayRemaid = day % 7;
                            if (dayRemaid > 0) {
                                builder.append(dayRemaid).append("天");
                            }
                        } else {
                            builder.append(day).append("天");
                        }
                    }
                }
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 计算年龄 到月
    public static int getAgeMonthByBirthday(String testTime, String birthday) throws ParseException {
        Calendar now = Calendar.getInstance();
        now.setTime(DateUtil.getDate_8(testTime));

        int ageMonth = 0;
        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            if (year > 0) {
                ageMonth += 12 * year;
            }
            if (month > 0) {
                ageMonth += month;
            }
        }
        return ageMonth;
    }

    public static void main(String args[]) throws ParseException {
        System.out.println(getAgeMonthByBirthday("2009-6-15", "2007-10-28"));
        System.out.println(getAgeMonthByBirthday("2018-7-6", "2018-6-28"));
        System.out.println(getAgeMonthByBirthday("2018-7-1", "2018-9-1"));
        System.out.println(getAgeMonthByBirthday("2018-10-1", "2018-7-3"));
        System.out.println(getAgeMonthByBirthday("2018-07-1", "2018-06-8"));
        System.out.println(getAgeMonthByBirthday("2018-7-1", "2016-4-5"));
        System.out.println(getAgeMonthByBirthday("2018-7-1", "2015-5-6"));
        // System.out.println("${password}".replaceAll("\\$\\{password\\}",
        // "111"));
        // System.out.println(getPregnancyStr(279));
        // System.out.println(getAgeMonDayByBirthday("2017-02-01"));
        // System.out.println(getAgeMonDayByBirthday("2016-01-05"));
    }

    // 宝宝月龄计算
    public static Map<String, Object> CalculateAgeOfMoon(Map<String, Object> map) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");// 小写的mm表示的是分钟
        // 宝宝月龄计算
        Calendar c = Calendar.getInstance();
        int day3 = 0;
        int month3 = 0;
        int year3 = 0;
        // 获取宝宝生日的年、月、日
        Date d = sdf.parse((String) map.get("birthday"));
        c.setTime(d);
        int year1 = c.get(Calendar.YEAR);
        int month1 = c.get(Calendar.MONTH) + 1;
        int day1 = c.get(Calendar.DAY_OF_MONTH);
        // 获取评估日期的年、月、日
        Date date = sdf.parse((String) map.get("createTime"));
        c.setTime(date);
        int year2 = c.get(Calendar.YEAR);
        int month2 = c.get(Calendar.MONTH) + 1;
        int day2 = c.get(Calendar.DAY_OF_MONTH);
        // 计算时间差
        if (day2 > day1 || day2 == day1) {
            // 创建日比出生日期的日大
            day3 = day2 - day1;
        } else {
            // 在创建日比出生日期的日小的情况下问月借1（一个月30天）
            if (month2 > month1) {
                // 创建月比出生日期月大
                day3 = day2 + 30 - day1;
                month2 = month2 - 1;
            } else {
                // 创建月比出生日期月小，需要从年份借1（一年12月）
                if (year2 > year1) {
                    day3 = day2 + 30 - day1;
                    month2 = month2 + 12 - 1;
                    year2 = year2 - 1;
                }
            }

        }
        // 创建月比出生日期月大
        if (month2 > month1) {
            month3 = month2 - month1;
        } else {
            // 创建月比出生日期月小，需要从年份借1（一年12月）
            if (year2 > year1) {
                month3 = month2 + 12 - month1;
                year2 = year2 - 1;
            }
        }
        if (year2 > year1) {
            year3 = year2 - year1;
        }
        map.clear();
        map.put("day3", day3);
        map.put("month3", month3);
        map.put("year3", year3);
        return map;

    }

    /**
     *
     * @Title: getXmlElementData
     * @Description: 解析xml获取子节点键值对
     * @param doc
     * @return IData
     * @author: ht
     */
    public static Map<String, Object> getXmlElementData(String xmlStr) {
        Map<String, Object> data = new HashMap<String, Object>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            org.w3c.dom.Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));

            org.w3c.dom.Element root = doc.getDocumentElement();
            NodeList nodeList = root.getChildNodes();
            if (nodeList != null) {
                getNodeList(nodeList, data);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     *
     * @Title: getNodeList
     * @Description: 获取子节点值
     * @param nodeList
     * @return IData
     * @author: ht
     */
    private static Map<String, Object> getNodeList(NodeList nodeList, Map<String, Object> data) {
        if (nodeList != null) {
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);
                if (childNode.hasChildNodes()) {
                    getNodeList(childNode.getChildNodes(), data);
                } else {
                    data.put(childNode.getParentNode().getNodeName(), childNode.getNodeValue());
                }
            }
        }
        return data;
    }

    /**
     *
     * @Title: getParam
     * @Description: 获取请求参数集合
     * @param request
     * @return IData
     * @author: ht
     */
    public static Map<String, Object> getParam(HttpServletRequest request) {
        Map<String, Object> param = new HashMap<String, Object>();
        Enumeration<?> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paramKey = (String) enu.nextElement();
            String value = request.getParameter(paramKey);
            // 中文转码
            try {
                value = new String(value.getBytes(Constants.ISO), Constants.UTF8);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            param.put(paramKey, value);
        }
        return param;
    }

    /**
     * 字典排序
     *
     * @param timestamp
     * @param nonce
     * @param token
     * @return
     * @throws Exception
     */
    public static String getSignature(String timestamp, String nonce, String token) throws Exception {
        String maxString = "";// 排后面
        String minString = "";// 排前面
        if (timestamp.compareTo(nonce) < 0) {
            maxString = nonce;
            minString = timestamp;
        } else {
            maxString = timestamp;
            minString = nonce;
        }

        if (token.compareTo(maxString) > 0) {
            token = minString + maxString + token;
        } else if (token.compareTo(minString) < 0) {
            token = token + minString + maxString;
        } else {
            token = minString + token + maxString;
        }
        return SHA1Encode(token);
    }

    /**
     * SHA1Encode
     *
     * @todo //sha1加密
     * @param sourceString
     * @return String
     * @Exception
     * @update:
     */
    public static String SHA1Encode(String sourceString) {
        String resultString = null;
        try {
            resultString = new String(sourceString);
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            resultString = byte2hexString(md.digest(resultString.getBytes()));
        } catch (Exception ex) {
        }
        return resultString;
    }

    /**
     * byte2hexString
     *
     * @todo
     * @param bytes
     * @return String
     * @Exception
     */
    public final static String byte2hexString(byte[] bytes) {
        StringBuffer buf = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            if (((int) bytes[i] & 0xff) < 0x10) {
                buf.append("0");
            }
            buf.append(Long.toString((int) bytes[i] & 0xff, 16));
        }
        return buf.toString().toUpperCase();
    }

    /**
     *
     * @Title: readStreamParameter
     * @Description: 从输入流读取post参数
     * @param in
     * @return String
     */
    public static String readStreamParameter(ServletInputStream in) {
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(in, Constants.UTF8));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }

}

class LogoConfig {
    // logo默认边框颜色
    public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;
    // logo默认边框宽度
    public static final int DEFAULT_BORDER = 2;
    // logo大小默认为照片的1/5
    public static final int DEFAULT_LOGOPART = 5;

    private final int border = DEFAULT_BORDER;
    private final Color borderColor;
    private final int logoPart;

    /**
     * Creates a default config with on color {@link #BLACK} and off color
     * {@link #WHITE}, generating normal black-on-white barcodes.
     */
    public LogoConfig() {
        this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);
    }

    public LogoConfig(Color borderColor, int logoPart) {
        this.borderColor = borderColor;
        this.logoPart = logoPart;
    }

    public Color getBorderColor() {
        return borderColor;
    }

    public int getBorder() {
        return border;
    }

    public int getLogoPart() {
        return logoPart;
    }

}
